#include <stdlib.h>
#include <i86.h>
#include <stdio.h>
#include <time.h>

#include "BaseType.h"
#include "pcitypes.h"
#include "pci.h"
#include "util.h"
#include "crc32.h"
#include "TraceLog.h"
#include "main.h"



/*
 * Payload Format

|<-----------------------------  Size   ---------------------------------->|
+-------------+--------------+--------------------------------+------------+
|    SOF      | Data Length  |          Data                  |    CRC32   |
+-------------+--------------+--------------------------------+------------+
|  4 bytes    |   4 bytes    |     variable length            |   4 bytes  |

 */
#define SOF   0x78563412
/*
 * fill up buffer according to the above format.
 * return value:
 * 1. Size < 12: CRC for the buffer
 * 2. Size >=12: CRC32 field as above.
 */
ULONG FillPayload( PUCHAR Buffer, ULONG Size, PULONG pMagicNum)
{
	ULONG i;
    ULONG ret;
	ASSERT( Buffer );
	ASSERT( Size > 0 );
	srand( (ULONG)time( NULL ) );
    if ( Size == 0 )
    {
        return 0;
    }
	if ( Size < 12 )
    {
        for( i = 0; i < Size; i++)
        {
            Buffer[ i ] = (UCHAR)( rand() & 0xFF );
        }
        ret = crc32( 0, Buffer, Size );
    }else{
        if ( pMagicNum )
        {
            *(PULONG)( Buffer )     = *pMagicNum;
        }else{
            *(PULONG)( Buffer )     = SOF;
        }
		*(PULONG)( Buffer + 4 ) = Size;
        for( i = 0; i < ( Size - 12 ); i++)
        {
            Buffer[ i + 8 ] = (UCHAR)( rand() & 0xFF );
        }
        ret = crc32( 0, Buffer + 8, ( Size - 12 ) );
		*(PULONG)( Buffer + Size - 4 ) = ret;
    }
    return ret;
}
STATUS CheckPayload( PUCHAR Buffer, ULONG Size, PULONG pMagicNum, PULONG Crc )
{
	ULONG crc;

	ASSERT( Buffer );
	ASSERT( Size > 0 );

	if ( Size >= 12 )
	{
        crc = ( pMagicNum == NULL ) ? SOF : (*pMagicNum );
		if ( *(PULONG)( Buffer ) != crc )
		{
			LogMsg( COMP_SCRIPT, DBG_ERROR, "Check Payload ERROR! SOF = %08X\n", *(PULONG)Buffer );
			return UNSUCCESSFUL;
		}
		if ( *(PULONG)( Buffer + 4 ) != ( Size - 12 ) )
		{
			LogMsg( COMP_SCRIPT, DBG_ERROR, "Check Payload ERROR! Length = %08X\n", *(PULONG)( Buffer + 4 ) );
			return UNSUCCESSFUL;
		}
		crc = crc32( 0, Buffer + 8, Size - 12 );
		if ( *(PULONG)( Buffer + Size - 4 ) != crc )
		{
			LogMsg( COMP_SCRIPT, DBG_ERROR, "Check Payload ERROR! Actual CRC %08X != Expected CRC %08X\n", crc, *(PULONG)( Buffer + Size - 4 ) );
			return UNSUCCESSFUL;
		}
        if ( Crc != NULL )
        {
            if ( crc != *Crc )
            {
                LogMsg( COMP_SCRIPT, DBG_ERROR, "Check Payload ERROR! Actual CRC %08X != Input CRC %08X\n", crc, *Crc );
                return UNSUCCESSFUL;
            }
        }
	}else{
        if ( Size > 0 )
        {
            crc = crc32( 0, Buffer, Size );
            if ( crc != *Crc )
            {
                LogMsg( COMP_SCRIPT, DBG_ERROR, "Check Payload ERROR! Actual CRC %08X != Input CRC %08X\n", crc, *Crc );
                return UNSUCCESSFUL;
            }
        }
    }
	return SUCCESS;
}
void PrintData( PUCHAR Data, ULONG Size, int comp, int level )
{
    int i;
    if ( ( Data == NULL ) || ( Size == 0 ) )
    {
        return;
    }
    i = Size;
    while( i + 16 < Size)
    {
        LogMsg( comp, level, "%02X %02X %02X %02X %02X %02X %02X %02X - %02X %02X %02X %02X %02X %02X %02X %02X\n",
            Data[ i ],
            Data[ i + 1 ],
            Data[ i + 2 ],
            Data[ i + 3 ],
            Data[ i + 4 ],
            Data[ i + 5 ],
            Data[ i + 6 ],
            Data[ i + 7 ],
            Data[ i + 8 ],
            Data[ i + 9 ],
            Data[ i + 10 ],
            Data[ i + 11 ],
            Data[ i + 12 ],
            Data[ i + 13 ],
            Data[ i + 14 ],
            Data[ i + 15 ]
            );
        i += 16;
    }
    switch( Size - i )
    {
    case 2 : LogMsg( comp, level, "%02X\n",                                                                     Data[ i ] ); break;
    case 3 : LogMsg( comp, level, "%02X %02X\n",                                                                Data[ i ], Data[ i+1 ]); break;
    case 4 : LogMsg( comp, level, "%02X %02X %02X\n",                                                           Data[ i ], Data[ i+1 ] , Data[ i+2] ); break;
    case 5 : LogMsg( comp, level, "%02X %02X %02X %02X\n",                                                      Data[ i ], Data[ i+1 ] , Data[ i+2], Data[ i+3 ] ); break;
    case 6 : LogMsg( comp, level, "%02X %02X %02X %02X %02X\n",                                                 Data[ i ], Data[ i+1 ] , Data[ i+2], Data[ i+3 ], Data[ i+4 ] ); break;
    case 7 : LogMsg( comp, level, "%02X %02X %02X %02X %02X %02X\n",                                            Data[ i ], Data[ i+1 ] , Data[ i+2], Data[ i+3 ], Data[ i+4 ], Data[ i+5 ] ); break;
    case 8 : LogMsg( comp, level, "%02X %02X %02X %02X %02X %02X %02X\n",                                       Data[ i ], Data[ i+1 ] , Data[ i+2], Data[ i+3 ], Data[ i+4 ], Data[ i+5 ], Data[ i+6 ] ); break;
    case 9 : LogMsg( comp, level, "%02X %02X %02X %02X %02X %02X %02X %02X\n",                                  Data[ i ], Data[ i+1 ] , Data[ i+2], Data[ i+3 ], Data[ i+4 ], Data[ i+5 ], Data[ i+6 ], Data[ i+7 ] ); break;
    case 10: LogMsg( comp, level, "%02X %02X %02X %02X %02X %02X %02X %02X - %02X\n",                           Data[ i ], Data[ i+1 ] , Data[ i+2], Data[ i+3 ], Data[ i+4 ], Data[ i+5 ], Data[ i+6 ], Data[ i+7 ], Data[ i+8 ] ); break;
    case 11: LogMsg( comp, level, "%02X %02X %02X %02X %02X %02X %02X %02X - %02X %02X\n",                      Data[ i ], Data[ i+1 ] , Data[ i+2], Data[ i+3 ], Data[ i+4 ], Data[ i+5 ], Data[ i+6 ], Data[ i+7 ], Data[ i+8 ], Data[ i+9 ] ); break;
    case 12: LogMsg( comp, level, "%02X %02X %02X %02X %02X %02X %02X %02X - %02X %02X %02X\n",                 Data[ i ], Data[ i+1 ] , Data[ i+2], Data[ i+3 ], Data[ i+4 ], Data[ i+5 ], Data[ i+6 ], Data[ i+7 ], Data[ i+8 ], Data[ i+9 ], Data[ i+10 ] ); break;
    case 13: LogMsg( comp, level, "%02X %02X %02X %02X %02X %02X %02X %02X - %02X %02X %02X %02X\n",            Data[ i ], Data[ i+1 ] , Data[ i+2], Data[ i+3 ], Data[ i+4 ], Data[ i+5 ], Data[ i+6 ], Data[ i+7 ], Data[ i+8 ], Data[ i+9 ], Data[ i+10 ], Data[ i+11 ] ); break;
    case 14: LogMsg( comp, level, "%02X %02X %02X %02X %02X %02X %02X %02X - %02X %02X %02X %02X %02X\n",       Data[ i ], Data[ i+1 ] , Data[ i+2], Data[ i+3 ], Data[ i+4 ], Data[ i+5 ], Data[ i+6 ], Data[ i+7 ], Data[ i+8 ], Data[ i+9 ], Data[ i+10 ], Data[ i+11 ], Data[ i+12 ] ); break;
    case 15: LogMsg( comp, level, "%02X %02X %02X %02X %02X %02X %02X %02X - %02X %02X %02X %02X %02X %02X\n",  Data[ i ], Data[ i+1 ] , Data[ i+2], Data[ i+3 ], Data[ i+4 ], Data[ i+5 ], Data[ i+6 ], Data[ i+7 ], Data[ i+8 ], Data[ i+9 ], Data[ i+10 ], Data[ i+11 ], Data[ i+12 ], Data[ i+13 ] ); break;
    }

}

/*****************************************************************************
 *
 *  Hardware Functions
 *
 ****************************************************************************/
//
//  DpmiMapPhysMemory()
//
//  Input:  start  - address of physical memory
//          length - length of memory map
//
//  Return: Address of linear mapped memory or NULL if not mapped
//
uint32_t DpmiMapPhysMemory(uint32_t start, uint32_t length)
{
        union REGS regs;

        regs.w.ax = 0x0800;
        regs.w.bx = start>>16;
        regs.w.cx = start&0xffff;
        regs.w.si = length>>16;
        regs.w.di = length&0xffff;

        int386(0x31, &regs, &regs);

        if(regs.w.cflag&INTR_CF)
                return 0;

        return ((regs.w.bx<<16)&0xffff0000)|regs.w.cx;
}

//
//  DpmiUnMapPhysMemory()
//
//  Input:  mapmem - address returned by DpmiMapPhysMemory
//
//  Return: Nothing
//
void DpmiUnMapPhysMemory(uint32_t mapmem)
{
        union REGS regs;

        regs.w.ax = 0x0801;
        regs.w.bx = mapmem>>16;
        regs.w.cx = mapmem&0xFFFF;

        int386(0x31, &regs, &regs);
}


PCHAR StatusToString( STATUS Status )
{
    switch( Status )
    {
    case SUCCESS:
        return "OK";
    case UNSUCCESSFUL:
        return "ERR";
    case ALLOCATE_MEM_FAILED:
        return "ALLOCATE_MEM_FAILED";
    case INIT_FAILED:
        return "INIT_FAILED";
    case DATA_XFER_LENGTH_ERROR:
        return "DATA_XFER_LENGTH_ERROR";
    case DATA_SIZE_TOO_LONG:
        return "DATA_SIZE_TOO_LONG";
    case SSD_PAGE_OVERWRITE:
        return "SSD_PAGE_OVERWRITE";
    case SSD_PAGE_NOT_WRITTEN:
        return "SSD_PAGE_NOT_WRITTEN";
    case TIME_OUT:
        return "TIME_OUT";
    case DATA_COMPARE_ERROR:
        return "DATA_COMPARE_ERROR";
    case LOOP_COMPLETED:
        return "LOOP_COMPLETED";
    default:
        return "N/A";
    }
}
#if 0
PCHAR CmdToString( HOST_REQ_TYPE Type )
{
    switch( Type )
    {
    case HOST_REQ_READ:
        return "READ";
    case HOST_REQ_WRITE:
        return "WRITE";
    case HOST_REQ_ERASE:
        return "ERASE";
    case HOST_REQ_OTHER:
        return "OTHER";
    case HOST_REQ_INVALID:
        return "INVLD";
    default:
        return "U/A";
    }
}
#endif

